Skip to content

Commit 18380e5

Browse files
Add new RestClient.DownloadStreamAsync() overload which accepts an error handler to process error responses
1 parent 36ebe2f commit 18380e5

File tree

2 files changed

+84
-4
lines changed

2 files changed

+84
-4
lines changed

src/RestSharp/RestClient.Async.cs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,50 @@ public async Task<RestResponse> ExecuteAsync(RestRequest request, CancellationTo
4040
/// <inheritdoc />
4141
[PublicAPI]
4242
public async Task<Stream?> DownloadStreamAsync(RestRequest request, CancellationToken cancellationToken = default) {
43+
return await DownloadStreamInternalAsync(request, null, cancellationToken);
44+
}
45+
46+
/// <inheritdoc />
47+
[PublicAPI]
48+
public async Task<Stream?> DownloadStreamAsync(RestRequest request, Action<RestResponse> errorHandler, CancellationToken cancellationToken = default) {
49+
return await DownloadStreamInternalAsync(request, errorHandler, cancellationToken);
50+
}
51+
52+
async Task<Stream?> DownloadStreamInternalAsync(RestRequest request, Action<RestResponse>? errorHandler, CancellationToken cancellationToken = default) {
4353
// Make sure we only read the headers so we can stream the content body efficiently
4454
request.CompletionOption = HttpCompletionOption.ResponseHeadersRead;
45-
var response = await ExecuteRequestAsync(request, cancellationToken).ConfigureAwait(false);
55+
var internalResponse = await ExecuteRequestAsync(request, cancellationToken).ConfigureAwait(false);
56+
57+
if (errorHandler != null) {
58+
if (internalResponse.Exception != null) {
59+
var response = GetErrorResponse(request, internalResponse.Exception, internalResponse.TimeoutToken);
60+
61+
errorHandler(response);
62+
}
63+
else if (internalResponse.ResponseMessage!.IsSuccessStatusCode == false) {
64+
var response = await RestResponse.FromHttpResponse(
65+
internalResponse.ResponseMessage!,
66+
request,
67+
Options.Encoding,
68+
internalResponse.CookieContainer?.GetCookies(internalResponse.Url),
69+
Options.CalculateResponseStatus,
70+
cancellationToken
71+
)
72+
.ConfigureAwait(false);
73+
74+
errorHandler(response);
75+
}
76+
}
4677

47-
var exception = response.Exception ?? response.ResponseMessage?.MaybeException();
78+
var exception = internalResponse.Exception ?? internalResponse.ResponseMessage?.MaybeException();
4879

4980
if (exception != null) {
5081
return Options.ThrowOnAnyError ? throw exception : null;
5182
}
5283

53-
if (response.ResponseMessage == null) return null;
84+
if (internalResponse.ResponseMessage == null) return null;
5485

55-
return await response.ResponseMessage.ReadResponseStream(request.ResponseWriter, cancellationToken).ConfigureAwait(false);
86+
return await internalResponse.ResponseMessage.ReadResponseStream(request.ResponseWriter, cancellationToken).ConfigureAwait(false);
5687
}
5788

5889
static RestResponse GetErrorResponse(RestRequest request, Exception exception, CancellationToken timeoutToken) {

test/RestSharp.Tests.Integrated/DownloadFileTests.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Net;
22
using System.Text;
3+
using RestSharp.Extensions;
34
using RestSharp.Tests.Shared.Fixtures;
45

56
namespace RestSharp.Tests.Integrated;
@@ -9,6 +10,7 @@ public DownloadFileTests() {
910
_server = HttpServerFixture.StartServer("Assets/Koala.jpg", FileHandler);
1011
var options = new RestClientOptions(_server.Url) { ThrowOnAnyError = true };
1112
_client = new RestClient(options);
13+
_clientNoThrow = new RestClient(_server.Url);
1214
}
1315

1416
public void Dispose() => _server.Dispose();
@@ -28,6 +30,7 @@ void FileHandler(HttpListenerRequest request, HttpListenerResponse response) {
2830

2931
readonly HttpServerFixture _server;
3032
readonly RestClient _client;
33+
readonly RestClient _clientNoThrow;
3134
readonly string _path = AppDomain.CurrentDomain.BaseDirectory;
3235

3336
[Fact]
@@ -65,6 +68,52 @@ public async Task Handles_Binary_File_Download() {
6568
Assert.Equal(expected, response);
6669
}
6770

71+
[Fact]
72+
public async Task Runs_ErrorHandler_On_Download_Request_Failure() {
73+
var client = new RestClient("http://localhost:12345");
74+
var request = new RestRequest("nonexisting");
75+
RestResponse? errorResponse = null;
76+
var stream = await client.DownloadStreamAsync(request, (r) => {
77+
errorResponse = r;
78+
});
79+
80+
Assert.Null(stream);
81+
Assert.NotNull(errorResponse);
82+
Assert.Equal(ResponseStatus.Error, errorResponse.ResponseStatus);
83+
}
84+
85+
[Fact]
86+
public async Task Runs_ErrorHandler_On_Download_Response_StatusCode_Not_Successful() {
87+
var request = new RestRequest("Assets/Koala1.jpg");
88+
RestResponse? errorResponse = null;
89+
var stream = await _clientNoThrow.DownloadStreamAsync(request, (r) => {
90+
errorResponse = r;
91+
});
92+
93+
Assert.Null(stream);
94+
Assert.NotNull(errorResponse);
95+
Assert.Equal(ResponseStatus.Completed, errorResponse.ResponseStatus);
96+
Assert.False(errorResponse.IsSuccessStatusCode);
97+
Assert.Equal(HttpStatusCode.NotFound, errorResponse.StatusCode);
98+
}
99+
100+
[Fact]
101+
public async Task Doesnt_Run_ErrorHandler_On_Download_Success() {
102+
var request = new RestRequest("Assets/Koala.jpg");
103+
RestResponse? errorResponse = null;
104+
var stream = await _clientNoThrow.DownloadStreamAsync(request, (r) => {
105+
errorResponse = r;
106+
});
107+
108+
Assert.NotNull(stream);
109+
Assert.Null(errorResponse);
110+
111+
var expected = await File.ReadAllBytesAsync(Path.Combine(_path, "Assets", "Koala.jpg"));
112+
var bytes = await stream.ReadAsBytes(CancellationToken.None);
113+
114+
Assert.Equal(expected, bytes);
115+
}
116+
68117
[Fact]
69118
public async Task Writes_Response_To_Stream() {
70119
var tempFile = Path.GetTempFileName();

0 commit comments

Comments
 (0)